package algo3.juegoCarmenSanDiego.modelo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

public class Juego {
	private Caso caso;
	private Policia policia;
	private Interpol interpol;
	private Map<String,Integer> mapJugadores = new HashMap<String,Integer>();
	private String nombreDelJugador;
	private String jugadorActual;
	private List<Ciudad> ciudadesDeOpcionParaElJugador=new ArrayList<Ciudad>();
	
	public Juego() throws Exception{
		this.policia = new Policia(null);
		this.cargarJugadores();
	}
	public Juego(String unaDireccion) throws SAXException, IOException, ParserConfigurationException{
		this.caso=new Caso(unaDireccion);
		this.policia = new Policia(caso.getCiudadDeLadronYPosicionarEnSiguiente());
		this.interpol = new Interpol();
		this.interpol.setNombreDeLadron(this.caso.getNombreDeLadron());
		this.cargarJugadores();
	}

	public void generarCaso() throws SAXException, IOException, ParserConfigurationException{
		this.interpol = new Interpol();
		Random random = new Random();
		int numeroRandom = random.nextInt(8) + 1;
		this.caso=new Caso("Caso"+Integer.toString(numeroRandom)+".xml");
		this.policia = new Policia(caso.getCiudadDeLadronYPosicionarEnSiguiente());
		this.policia.setCasosGanados(this.mapJugadores.get(this.jugadorActual));
		this.interpol.setNombreDeLadron(this.caso.getNombreDeLadron());
		this.generarCiudadesAlzarParaElPolicia();
	}
	public void setJugadorActual(String unNombre){
		this.jugadorActual = unNombre;
	}
	
	public String quePoliciaBusquePistaEn(TipoEdificioEnum unTipoEdificio) throws Exception{
		return this.policia.visitar(unTipoEdificio, this.caso);
	}
	public boolean policiaPudoViajar(Ciudad ciudadDestino){
		policia.viajar(ciudadDestino);
		return policia.getAcaboElCasoParaElJugador();
	}
	public Ciudad getCiudadDelPolicia(){
		return this.policia.getCiudad();
	}
	public void generarCiudadesAlzarParaElPolicia(){
		this.ciudadesDeOpcionParaElJugador=this.caso.getCiudadesParaMostrarAlPolicia();
	}
	public List<Ciudad> ciudadesDeOpcionParaElJugador(){
		return this.ciudadesDeOpcionParaElJugador;
	}
	
	public void emitirOrdenDeArresto(String unSexo,String unHobby,String unPelo,String unaSenia,String unCoche) throws ExcepcionTiempo{
		this.policia.emitirOrdenDeArresto(this.interpol, unSexo, unHobby, unPelo, unaSenia, unCoche);
	}
	public String getObjetoRobado() {
		return this.caso.getObjetoRobado();
	}
	public String getNombreCiudadInicio() {
		return caso.getNombreCiudadInicio();
	}
	
	public void cargarJugadores() throws ParserConfigurationException, SAXException, IOException{
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.newDocument();
		
		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		
		File archivo = new File("jugadores.xml");
		doc = dBuilder.parse(archivo);
			Element elementoJugadores = (Element)doc.getElementsByTagName("jugadores").item(0);
			
			for(int i=0; i< elementoJugadores.getChildNodes().getLength(); i++) {
				
				Element elementoDeJugador=(Element) elementoJugadores.getChildNodes().item(i);
				this.mapJugadores.put(elementoDeJugador.getAttribute("nombre"),Integer.parseInt(elementoDeJugador.getAttribute("casosGanados")));
			}
	}
	public void guardarJugadores() throws ParserConfigurationException, TransformerException{
		
		incrementarCasosGanadosSiEljugadorGanoElCaso();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.newDocument();
		
		Element elementoDeJugadores= doc.createElement("jugadores");
	    for (Entry<String, Integer> jugador: mapJugadores.entrySet()) {
	    	
	    	Element elementoDeJugador=doc.createElement("jugador");
			elementoDeJugador.setAttribute("nombre",jugador.getKey());
			elementoDeJugador.setAttribute("casosGanados",Integer.toString(jugador.getValue()));
			elementoDeJugadores.appendChild(elementoDeJugador);
	    }
	    doc.appendChild(elementoDeJugadores);
		
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		DOMSource source = new DOMSource(doc);
		File archivoDestino = new File("jugadores.xml");
		StreamResult result = new StreamResult(archivoDestino);
		transformer.transform(source, result);
	}
	public void AgregarJugador(String unNombre,int cantidadDeCasosGanados){
		this.mapJugadores.put(unNombre, cantidadDeCasosGanados);
	}
	
	public void asignarRangoApolicia(){
		int numeroDeCasosGanados = mapJugadores.get(this.jugadorActual);
		if (numeroDeCasosGanados < 5)
			this.policia.setRangoDePolicia(new Novato());
		else if(numeroDeCasosGanados< 10)
				this.policia.setRangoDePolicia(new Detective());
			else if(numeroDeCasosGanados < 20)
				this.policia.setRangoDePolicia(new Investigador());
			else this.policia.setRangoDePolicia(new Sargento());
	}
	
	public void setCasosGanadosDeJugador(String unNombre,int casosGanados){
		mapJugadores.remove(unNombre);
		this.mapJugadores.put(unNombre,casosGanados);
	}
	public int obtenerCantidadDeCasosGandos(String unNombre){
		Integer cantidad=this.mapJugadores.get(unNombre);
		if(cantidad ==null){
			this.AgregarJugador(unNombre, 0);
			return 0;
		}
		else{
			return this.mapJugadores.get(unNombre);
		}
	}
	public Map<Integer ,String> getCaracteristicasSospechoso(){
		return this.interpol.getCaracteristicasSospechoso();
	}
	
	public String getSospechosoSexo(){
		return this.interpol.getSospechosoSexo();
	}
	public String getSospechosoHobby(){
		return this.interpol.getSospechosoHobby();
	}
	public String getSospechosoSenia(){
		return this.interpol.getSospechosoSenia();
	}
	public String getSospechosoCoche(){
		return this.interpol.getSospechosoCoche();
	}
	public String getSospechosoPelo(){
		return this.interpol.getSospechosoPelo();
	}
	
	public void setNombreDelJugador(String nombreDelJugador) {
		this.nombreDelJugador = nombreDelJugador;
	}
	public String getNombreDelJugador() {
		return nombreDelJugador;
	}
	public int getTiempoRestante() {
		return this.policia.getTiempoRestante();
	}
	public Policia getPolicia(){
		return this.policia;
	}
	
	public Policia getPolicia(String nombre){
		this.policia.setCasosGanados(obtenerCantidadDeCasosGandos(nombre));
		return this.policia;
	}
	
	
	public void setSexoDelSospechoso(String sexo) {
		interpol.setSospechosoSexo(sexo);		
	}
	public void setSeniaDelSospechoso(String senia) {
		interpol.setSospechosoSenia(senia);		
	}
	public void setHobbyDelSospechoso(String hobby) {
		interpol.setSospechosoHobby(hobby);		
	}
	public void setCocheDelSospechoso(String coche) {
		interpol.setSospechosoCoche(coche);		
	}
	public void setPeloDelSospechoso(String pelo) {
		interpol.setSospechosoPelo(pelo);		
	}
	public Interpol getInterpol() {
		return this.interpol;
	}
	public List<String> listaDeLadronesSospechosos() {
		return this.policia.getListaDeSospechosos();
		
	}
	public boolean emitirArresto() {
			return this.policia.emitirArresto(this.interpol);
	}
	public String getNombreCiudadPolicia() {
		return this.policia.getCiudad().getNombreDeCiudad();
	}
	public String getNombreCiudadDeEscondite() {
		return this.caso.getNombreCiudadDeEscondite();
	}
	public boolean quePoliciaIntenteAtraparLadron(TipoEdificioEnum unEdificio,TipoEdificioEnum edificioEscondite) {
		return this.policia.intentarAtraparLadron(unEdificio,edificioEscondite);
	}
	public TipoEdificioEnum getEdificioDeEscondite() {
		return this.caso.edificioDeEsconditeDelLadron();
	}
	public String getMensajeQueTienePolicia() {
		return this.policia.getMensajeAcumulado();
	}
	public Caso getCaso(){
		return this.caso;
	}

	//devuelve true en caso de que el jugador exista en la base de datos. false, en caso contrario.
	public boolean setearJugadorActual(String nombre) {
		this.jugadorActual = nombre;
		return this.mapJugadores.containsKey(nombre);
	}

	public void AgregarJugador(String nombre) {
		this.mapJugadores.put(nombre, 0);
	}

	private void incrementarCasosGanadosSiEljugadorGanoElCaso() throws ParserConfigurationException, TransformerException {
			mapJugadores.remove(this.jugadorActual);
			this.mapJugadores.put(this.jugadorActual, policia.getCasosGanados());
	}
	public Rango getRangoPolicia() {
		return this.policia.getRangoDePolicia();
	}
}